frontend/pages/e/[uuid]/index.tsx (view raw)
1import {useState, useReducer, useEffect} from 'react';
2import {makeStyles} from '@material-ui/core/styles';
3import {useTranslation} from 'react-i18next';
4import {initializeApollo} from '../../../lib/apolloClient';
5import useToastStore from '../../../stores/useToastStore';
6import useEventStore from '../../../stores/useEventStore';
7import Layout from '../../../layouts/Default';
8import AddToMyEventDialog from '../../../containers/AddToMyEventDialog';
9import TravelColumns from '../../../containers/TravelColumns';
10import NewTravelDialog from '../../../containers/NewTravelDialog';
11import VehicleChoiceDialog from '../../../containers/VehicleChoiceDialog';
12import WelcomeDialog from '../../../containers/WelcomeDialog';
13import EventBar from '../../../containers/EventBar';
14import Loading from '../../../containers/Loading';
15import OnBoardingTour from '../../../containers/OnBoardingTour';
16import {
17 useUpdateEventMutation,
18 Event as EventType,
19 useEventByUuidQuery,
20 EventByUuidDocument,
21 EditEventInput,
22 useFindUserVehiclesQuery,
23} from '../../../generated/graphql';
24import ErrorPage from '../../_error';
25import useProfile from '../../../hooks/useProfile';
26import Fab from '../../../containers/Fab';
27import useMediaQuery from '@material-ui/core/useMediaQuery';
28import useBannerStore from '../../../stores/useBannerStore';
29import DrawerMenu from '../../../containers/DrawerMenu';
30
31const POLL_INTERVAL = 10000;
32
33interface Props {
34 event: EventType;
35 eventUUID: string;
36}
37
38const EventPage = props => {
39 const {t} = useTranslation();
40 const {event} = props;
41 if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
42 return <Event {...props} />;
43};
44
45const Event = (props: Props) => {
46 const {eventUUID} = props;
47 const bannerOffset = useBannerStore(s => s.offset);
48 const classes = useStyles({bannerOffset});
49 const {t} = useTranslation();
50 const {user} = useProfile();
51 const {data: {me: {profile: {vehicles = []} = {}} = {}} = {}, loading} =
52 useFindUserVehiclesQuery();
53 const addToast = useToastStore(s => s.addToast);
54 const setEvent = useEventStore(s => s.setEvent);
55 const eventUpdate = useEventStore(s => s.event);
56 const setIsEditing = useEventStore(s => s.setIsEditing);
57 const [updateEvent] = useUpdateEventMutation();
58 const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
59 const [openNewTravelContext, toggleNewTravel] = useState({opened: false});
60 const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
61 const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
62 pollInterval: POLL_INTERVAL,
63 variables: {uuid: eventUUID},
64 });
65
66 const onSave = async e => {
67 try {
68 const {uuid, ...data} = eventUpdate;
69 const {id, __typename, travels, users, waitingList, ...input} = data;
70 await updateEvent({
71 variables: {uuid, eventUpdate: input as EditEventInput},
72 refetchQueries: ['eventByUUID'],
73 });
74 setIsEditing(false);
75 } catch (error) {
76 console.error(error);
77 addToast(t('event.errors.cant_update'));
78 }
79 };
80
81 useEffect(() => {
82 if (event) setEvent(event as EventType);
83 }, [event]);
84
85 const addTravelClickHandler =
86 user && vehicles?.length != 0
87 ? toggleVehicleChoice
88 : () => toggleNewTravel({opened: true});
89
90 if (!event || loading) return <Loading />;
91
92 return (
93 <Layout
94 className={classes.layout}
95 pageTitle={t('event.title', {title: event.name})}
96 menuTitle={t('event.title', {title: event.name})}
97 displayMenu={false}
98 >
99 <EventBar event={event} onAdd={setIsAddToMyEvent} onSave={onSave} />
100 <DrawerMenu />
101 <TravelColumns toggle={addTravelClickHandler} />
102 <Fab
103 onClick={addTravelClickHandler}
104 aria-label="add-car"
105 color="primary"
106 className={classes.bottomRight}
107 >
108 {t('travel.creation.title')}
109 </Fab>
110 <NewTravelDialog
111 context={openNewTravelContext}
112 toggle={() => toggleNewTravel({opened: false})}
113 />
114 <VehicleChoiceDialog
115 open={openVehicleChoice}
116 toggle={toggleVehicleChoice}
117 toggleNewTravel={toggleNewTravel}
118 vehicles={vehicles}
119 />
120 <AddToMyEventDialog
121 event={event}
122 open={isAddToMyEvent}
123 onClose={() => setIsAddToMyEvent(false)}
124 />
125 <WelcomeDialog />
126 <OnBoardingTour />
127 </Layout>
128 );
129};
130
131export async function getServerSideProps(ctx) {
132 const {uuid} = ctx.query;
133 const apolloClient = initializeApollo();
134 const {data = {}} = await apolloClient.query({
135 query: EventByUuidDocument,
136 variables: {uuid},
137 });
138 const {eventByUUID: event} = data;
139 const {host = ''} = ctx.req.headers;
140
141 return {
142 props: {
143 event,
144 eventUUID: uuid,
145 metas: {
146 title: event?.name || '',
147 url: `https://${host}${ctx.resolvedUrl}`,
148 },
149 },
150 };
151}
152
153const useStyles = makeStyles(theme => ({
154 layout: ({bannerOffset}) => ({
155 paddingTop: theme.mixins.toolbar.minHeight + bannerOffset,
156 }),
157 bottomRight: {
158 bottom: 0,
159 right: theme.spacing(6),
160
161 [theme.breakpoints.down('sm')]: {
162 right: theme.spacing(1),
163 bottom: 56,
164 },
165 },
166}));
167
168export default EventPage;